#ifndef AVALON_BASICISTREAMREADER_HPP
#define AVALON_BASICISTREAMREADER_HPP
#include <istream>
#include "Avalon/Base/Handle.hpp"
#include "Avalon/IO/Buffer.hpp"
#include "Avalon/IO/Reader.hpp"

namespace Avalon {
namespace IO {

  /*! \class BasicIStreamReader
   *  \brief Wraps an std::basic_istream for use with the Reader interface.
   *  \author Kamal Mansouri <kranar@hotmail.com>
   */
  template<typename _Elem = char, typename _Traits = std::char_traits<_Elem>>
  class BasicIStreamReader : public Reader {
    public:

      //! Constructs a BasicIStreamReader.
      /*!
        \param source The basic_istream to wrap.
      */
      BasicIStreamReader(Carry<std::basic_istream<_Elem, _Traits>> source)
          : m_source(source) {}

      virtual ~BasicIStreamReader() {}

      virtual bool IsAtEndOfDataSource() {
        return m_source->eof();
      }

      virtual Threading::Async<int>::Ptr Read(Buffer* destination) {
        const int READ_SIZE = 1024;
        bool keepReading = true;
        int sizeRead = 0;
        while(keepReading) {
          destination->Reserve(sizeRead + READ_SIZE);
          m_source->read(destination->GetMutableData() + sizeRead, READ_SIZE);
          int result = static_cast<int>(m_source->gcount());
          sizeRead += result;
          keepReading = (result != 0);
        }
        return Threading::NewAsync(static_cast<int>(sizeRead));
      }

      virtual Threading::Async<int>::Ptr Read(void* destination, int size) {
        m_source->read(static_cast<char*>(destination), size);
        return Threading::NewAsync(static_cast<int>(m_source->gcount()));
      }

      virtual Threading::Async<int>::Ptr Read(Buffer* destination, int size) {
        m_source->read(destination->GetMutableData(), size);
        return Threading::NewAsync(static_cast<int>(m_source->gcount()));
      }

    private:
      Handle<std::basic_istream<_Elem, _Traits>> m_source;
  };
}
}

#endif // AVALON_BASICISTREAMREADER_HPP
